#region File Description
//-----------------------------------------------------------------------------
// GameplayScreen.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Minestorm.Retro.GameLogic;
using Minestorm.Retro.Screens;
using Minestorm.Screens;
#endregion

namespace Minestorm.Retro.Screens
{
    /// <summary>
    /// This screen implements the actual game logic. It is just a
    /// placeholder to get the idea across: you'll probably want to
    /// put some more interesting gameplay in here!
    /// </summary>
    class GameplayScreen : GameScreen
    {
        #region Fields

        ContentManager content;
        SpriteFont gameFont;
        Level level;
        BloomComponent bloomComponent;
        TextureManager textureManager;
        SoundManager soundManager;
        RenderTarget2D renderTarget;
        Texture2D overlayTexture;

        float pauseAlpha;

        #endregion

        #region Initialization


        /// <summary>
        /// Constructor.
        /// </summary>
        public GameplayScreen()
        {
            
            TransitionOnTime = TimeSpan.FromSeconds(1.5);
            TransitionOffTime = TimeSpan.FromSeconds(0.5);

            textureManager = new TextureManager();
            soundManager = new SoundManager();

            //levelSettings[0] = new LevelSettings() { MineTypes = new MineType[] { MineType.Floating, MineType.Floating, MineType.Floating, MineType.Floating, MineType.Floating, MineType.Floating, MineType.Floating, MineType.Floating, MineType.Floating, MineType.Floating } };
            //levelSettings[1] = new LevelSettings() { MineTypes = new MineType[] { MineType.Floating } };
            //levelSettings[2] = new LevelSettings() { MineTypes = new MineType[] { MineType.Floating } };
            //levelSettings[3] = new LevelSettings() { MineTypes = new MineType[] { MineType.Floating } };
            //levelSettings[4] = new LevelSettings() { MineTypes = new MineType[] { MineType.Floating } };
            levelSettings[0] = new LevelSettings() { MineTypes = new MineType[] { MineType.Floating, MineType.Floating, MineType.Floating, MineType.Floating } };
            levelSettings[1] = new LevelSettings() { MineTypes = new MineType[] { MineType.Floating, MineType.Floating, MineType.Floating, MineType.Fireball } };
            levelSettings[2] = new LevelSettings() { MineTypes = new MineType[] { MineType.Floating, MineType.Floating, MineType.Floating, MineType.Magnetic } };
            levelSettings[3] = new LevelSettings() { MineTypes = new MineType[] { MineType.Floating, MineType.Floating, MineType.Floating, MineType.MagneticFireball } };
            levelSettings[4] = new LevelSettings() { MineTypes = new MineType[] { MineType.Floating, MineType.Floating, MineType.Magnetic, MineType.Fireball } };
            levelSettings[5] = new LevelSettings() { MineTypes = new MineType[] { MineType.Floating, MineType.Floating, MineType.MagneticFireball, MineType.Fireball } };
            levelSettings[6] = new LevelSettings() { MineTypes = new MineType[] { MineType.Floating, MineType.Floating, MineType.MagneticFireball, MineType.Magnetic } };
            levelSettings[7] = new LevelSettings() { MineTypes = new MineType[] { MineType.Floating, MineType.Floating, MineType.Fireball, MineType.Fireball } };
            levelSettings[8] = new LevelSettings() { MineTypes = new MineType[] { MineType.Floating, MineType.Floating, MineType.Magnetic, MineType.Magnetic } };
            levelSettings[9] = new LevelSettings() { MineTypes = new MineType[] { MineType.Floating, MineType.Floating, MineType.MagneticFireball, MineType.MagneticFireball } };
            levelSettings[10] = new LevelSettings() { MineTypes = new MineType[] { MineType.Floating, MineType.Fireball, MineType.Fireball, MineType.Fireball } };
            levelSettings[11] = new LevelSettings() { MineTypes = new MineType[] { MineType.Floating, MineType.Magnetic, MineType.Magnetic, MineType.Magnetic } };
            levelSettings[12] = new LevelSettings() { MineTypes = new MineType[] { MineType.Floating, MineType.MagneticFireball, MineType.MagneticFireball, MineType.MagneticFireball } };
        }

        private enum LoadReason
        {
            Started,
            Died,
            Won,
            Ended
        }

        /// <summary>
        /// Load graphics content for the game.
        /// </summary>
        public override void LoadContent()
        {
            if (content == null)
                content = new ContentManager(ScreenManager.Game.Services, "Content");

            gameFont = content.Load<SpriteFont>("gamefont");

            textureManager.LoadContent(content);
            soundManager.LoadContent(content);

            overlayTexture = content.Load<Texture2D>("overlay");

            // A real game would probably have more content than this sample, so
            // it would take longer to load. We simulate that by delaying for a
            // while, giving you a chance to admire the beautiful loading screen.
            Thread.Sleep(1000);

            // once the load has finished, we use ResetElapsedTime to tell the game's
            // timing mechanism that we have just finished a very long frame, and that
            // it should not try to catch up.
            ScreenManager.Game.ResetElapsedTime();

            LoadLevel(LoadReason.Started);

            bloomComponent = new BloomComponent(ScreenManager.Game);
            bloomComponent.Settings = new BloomSettings(null, 0.25f, 4, 2, 1, 2, 0);

            bloomComponent.Initialize();

            var graphics = ScreenManager.Game.GraphicsDevice;

            var pp = graphics.PresentationParameters;
            var format = pp.BackBufferFormat;

            var width = pp.BackBufferWidth;
            var height = pp.BackBufferHeight;

            renderTarget = new RenderTarget2D(ScreenManager.Game.GraphicsDevice, width, height, false, format, pp.DepthStencilFormat, pp.MultiSampleCount, RenderTargetUsage.DiscardContents);
        }

        LevelSettings[] levelSettings = new LevelSettings[13];
        int currentLevel = 0;

        private void LoadLevel(LoadReason reason)
        {
            if (reason == LoadReason.Won)
                currentLevel++;

            if (currentLevel < levelSettings.Length)
            {
                var score = 0;
                var lives = 4;

                if (level != null)
                {
                    score = level.Score;
                    lives = level.Lives;
                    level.UnloadContent();
                }

                if (reason == LoadReason.Died)
                    lives--;
                if (reason == LoadReason.Won && currentLevel % 4 == 0)
                    lives++;

                level = new Level(ScreenManager, lives, score, currentLevel + 1, levelSettings[currentLevel], textureManager, soundManager, content);
            }
            else
                Win();
        }

        public void Win()
        {
        }
        
        /// <summary>
        /// Unload graphics content used by the game.
        /// </summary>
        public override void UnloadContent()
        {
            content.Unload();

            if (level != null)
            {
                level.UnloadContent();
                level = null;
            }

            textureManager.UnloadContent();
            soundManager.UnloadContent();

            overlayTexture.Dispose();

            bloomComponent.Dispose();
            bloomComponent = null;
        }


        #endregion

        #region Update and Draw

        private GameTime _gameTime;

        /// <summary>
        /// Updates the state of the game. This method checks the GameScreen.IsActive
        /// property, so the game will stop updating when the pause menu is active,
        /// or if you tab away to a different application.
        /// </summary>
        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
                                                       bool coveredByOtherScreen)
        {
            _gameTime = gameTime;

            base.Update(gameTime, otherScreenHasFocus, false);

            if (level == null)
                return;

            // Gradually fade in or out depending on whether we are covered by the pause screen.
            if (coveredByOtherScreen)
                pauseAlpha = Math.Min(pauseAlpha + 1f / 32, 1);
            else
                pauseAlpha = Math.Max(pauseAlpha - 1f / 32, 0);

            if (IsActive)
            {
                level.Update(gameTime);

                if (level.LevelState != LevelState.Playing)
                {
                    if (level.LevelState == LevelState.GameOver)
                    {
                        ExitScreen();
                        ScreenManager.AddScreen(new GameTypeScreen(), null);
                        return;
                    }

                    LoadLevel(level.LevelState == LevelState.Finished_Dead ? LoadReason.Died : LoadReason.Won);
                }
            }
        }


        /// <summary>
        /// Lets the game respond to player input. Unlike the Update method,
        /// this will only be called when the gameplay screen is active.
        /// </summary>
        public override void HandleInput(InputState input)
        {
            if (input == null)
                throw new ArgumentNullException("input");

            // Look up inputs for the active player profile.
            int playerIndex = (int)ControllingPlayer.Value;

            KeyboardState keyboardState = input.CurrentKeyboardStates[playerIndex];
            GamePadState gamePadState = input.CurrentGamePadStates[playerIndex];

            // The game pauses either if the user presses the pause button, or if
            // they unplug the active gamepad. This requires us to keep track of
            // whether a gamepad was ever plugged in, because we don't want to pause
            // on PC if they are playing with a keyboard and have no gamepad at all!
            bool gamePadDisconnected = !gamePadState.IsConnected &&
                                       input.GamePadWasConnected[playerIndex];

            if (input.IsPauseGame(ControllingPlayer) || gamePadDisconnected)
            {
                //soundManager.Pause();
                level.Pause();
                ScreenManager.AddScreen(new PauseMenuScreen(), ControllingPlayer);
            }
            else
            {
                //soundManager.Resume();
                level.Resume();
                if (level != null)
                    level.HandleInput(input, _gameTime);
            }
        }


        /// <summary>
        /// Draws the gameplay screen.
        /// </summary>
        public override void Draw(GameTime gameTime)
        {
            if (level == null)
                return;

            ScreenManager.GraphicsDevice.SetRenderTarget(null);

            bloomComponent.BeginDraw(renderTarget);

            ScreenManager.GraphicsDevice.Clear(ClearOptions.Target,
                                               Color.Black, 0, 0);

            ScreenManager.GraphicsDevice.SetRenderTarget(renderTarget);

            level.Draw(gameTime);

            bloomComponent.Draw(gameTime);
            
            //level.DrawBounds();

            var screenW = ScreenManager.Game.GraphicsDevice.Viewport.Width;
            var screenH = ScreenManager.Game.GraphicsDevice.Viewport.Height;

            ScreenManager.GraphicsDevice.SetRenderTarget(null);

            ScreenManager.SpriteBatch.Begin();
            ScreenManager.SpriteBatch.Draw(textureManager.GetTexture("gameplay_bg"), new Rectangle(0, 0, screenW, screenH), Color.White);

            var targetRect = new Rectangle(screenW / 2 - 185, screenH / 2 - 231, 370, 462);

            ScreenManager.SpriteBatch.Draw(renderTarget,targetRect, targetRect, Color.White);

            ScreenManager.SpriteBatch.Draw(overlayTexture, targetRect, Color.White);

            ScreenManager.SpriteBatch.End();
        }


        #endregion
    }
}
